/**
 * @module 等值判断和类型判断相关
 */
// == 运算符
// null 和 undefined 与其他类型比较时，结果都为false
// null 和 undefined 之间的比较结果为true
// console.log(null == 0) // false
// console.log(null == null) // true
// console.log(null == undefined) // true
// console.log(undefined == 0) // false
// console.log('0' == false) // true
// console.log('' == false) // true
//  NaN 不等于任何值，包括自身
// console.log(NaN == NaN) // false
// bigInt ,Symbol 类型对象 == 时 会先转换为原始类型的值 再进行比较
// console.log(1n == 1) // true
// console.log(1n == '1') // true
// console.log(1n == true) // true
// console.log(0n == false) // true
// console.log(1n == Number(1)) // true

// typeof 性能比 instanceof 高；当判断达到一定数量级时，typeof 性能优势明显 百万级别时为instanceof的2倍左右
// typeof 可以判断基本类型，instanceof 不能判断基本类型
// console.log(typeof 1) // number
// console.log(typeof '1') // string
// console.log(typeof true) // boolean
// console.log(typeof undefined) // undefined
// console.log(typeof Symbol()) // symbol
// console.log(typeof null) // object
// console.log(typeof []) // object
// console.log(typeof {}) // object
// console.log(typeof console.log) // function
// console.log(typeof console.log()) // undefined
// console.log(typeof console.log(1)) // undefined
// console.log(1 instanceof Number) // false
// console.log('1' instanceof String) // false
// console.log(true instanceof Boolean) // false
// console.log(undefined instanceof Object) // false
// console.log(Symbol() instanceof Symbol) // false
// console.log(null instanceof Object) // false
// console.log([] instanceof Array) // true
// console.log({} instanceof Object) // true
// console.log(console.log instanceof Function) // true
// console.log(console.log() instanceof Function) // false
// console.log(console.log(1) instanceof Function) // false

// null是一个关键字，undefined是一个全局变量
// var print = console.log
// print(Object.getOwnPropertyDescriptor(global, 'null')) // undefined 无法获取
// print(Object.getOwnPropertyDescriptor(global, 'undefined'))
// 全局变量undefined的属性特性
// {
//     value: undefined,
//     writable: false,
//     enumerable: false,
//     configurable: false
//   }

// typeof 主要用途： 操作数的类型，只能识别基础数据类型和引用类型，引用类型进一步判断，需要其他方法辅助
// console.log(typeof null) // object
// console.log(typeof NaN) // number
// console.log(typeof document.all) // undefined

// constructor 主要用途： 操作数的构造函数
// null 和 undefined 没有构造函数
// console.log(null.constructor) // 报错
// constructor函数可以被修改
// var a = '1'
// console.log(a.constructor) // [Function: String]
// String.prototype.constructor = function a() {}
// console.log(a.constructor) // [Function: a]

// instanceof 主要用途： 原型链上查找，查到即是其实例
// 注意事项 右操作对象必须是函数或者class 判断右操作数是否在左操作数的原型链上

// isPrototypeOf 主要用途： 是否出现在实例对象的原型链上 没有操作对象必须是函数或者class的限制，比instanceof更加安全
// 注意事项 判断左操作数是否在右操作数的原型链上 与 instanceof 相反；能正常返回结果的前提下，基本等同于 instanceof

// toString 主要用途： 通过函数的动态this特性，返回数据类型
// console.log(Object.prototype.toString.call(Boolean.prototype)) // [object Boolean]
// console.log(Object.prototype.toString.call(Number.prototype)) // [object Number]
// console.log(Object.prototype.toString.call(123)) // [object Number]
// console.log(Object.prototype.toString.call({})) // [object Object]
// console.log(Object.prototype.toString.call([])) // [object Array]
// console.log(Object.prototype.toString.call(null)) // [object Null]
// console.log(Object.prototype.toString.call(NaN)) // [object Number]
// console.log(Object.prototype.toString.call(Date.prototype)) // [object Object]
// const date = new Date()
// console.log(Object.prototype.toString.call(date)) // [object Date]
// console.log(Object.prototype.toString.call(RegExp.prototype)) // [object Object]
// const regExp = new RegExp()
// console.log(Object.prototype.toString.call(regExp)) // [object RegExp]

// console.log(typeof Boolean.prototype) // object
// console.log(typeof Number.prototype) // object
// const date = new Date()
// console.log(typeof date) // object

// Symbol.toStringTag
// ES6 引入了Symbol.toStringTag属性，适用于需要自定义类型的场景，比如自定义类
// 一般配合Object.prototype.toString.call()使用
// class MyArray {
// 	get [Symbol.toStringTag]() {
// 		return 'MyArray'
// 	}
// }
// var pf = console.log
// var a = new MyArray()

// console.log(a.toString()) // [object MyArray]
// console.log(Object.prototype.toString.call(a)) // [object MyArray]

// undefined和void 0 === 为true
// const isUndefined = obj => {
// 	return obj === void 0 // void 0 === undefined;void 100 === undefined void后面不管跟什么值都是undefined
// }
// console.log(void 0)
// console.log(isUndefined(undefined)) // true

// isNaN 函数实现方式类似如下 isNaN不能判断bigint和Symbol类型
// const isNaN = function (value) {
// 	return Object.is(Number(value), NaN)
// }
// console.log(isNaN(NaN)) // true

// isNaN 传入bigint或者Symbol类型会报错

// Number.isNaN 判断一个值是否是数字，并且值等于NaN
// Number.isNaN 函数实现方式类似如下
// isNaN3 = function (value) {
// 	if (typeof value !== 'number') {
// 		return false
// 	}
// 	return Object.is(value, NaN)
// }
// console.log(isNaN3(1n)) // true

// 数组的indexOf和includes方法本质上的区别
// const arr = [NaN]
// console.log(arr.indexOf(NaN)) // -1
// console.log(arr.includes(NaN)) // true
// 以上的结果是因为indexOf内部使用的是Number::equal方法，includes内部使用的是Number::sameValueZero方法
// indexOf内部使用的是Number::equal方法
// includes内部使用的是Number::sameValueZero方法

// Number的sameValueZero方法 认为+0和-0是相同的，认为NaN和NaN是相同的
// 1 如果x和y的类型不相同，返回false
// 2 如果x的类型为number
// 2.1 如果x和y是NaN，返回true
// 2.2 如果x和y是+0或者-0，返回true
// 2.4 如果x和y是同一个值，返回true
// 2.5 其他情况返回false

// const arr = [+0]
// console.log(arr.indexOf(0n)) // -1
// console.log(arr.includes(0n)) // false

// Object.is 认为+0和-0是不等的，认为NaN和NaN是相同的

// Number的sameValue方法 认为+0和-0是不等的，-0和0是不等的 +0和0是相等的 认为NaN和NaN是相等的

// 比较运算对应关系
// isLooselyEqual === ==
// isStrictlyEqual === ===  Array的[last]index[Of]方法和switch的case内部使用的是isStrictlyEqual
// isSameValue === Object.is
// isSameValueZero 被许多内置运算使用
